package com.flash.dataU.test.controller;

import com.flash.dataU.test.entity.Project;
import com.flash.dataU.test.entity.Server;
import com.flash.dataU.test.entity.ServerType;
import com.flash.dataU.test.service.impl.ProjectService;
import com.flash.dataU.test.service.impl.ServerService;
import com.flash.dataU.test.service.impl.ServerTypeService;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * .
 *
 * @author sunym1993
 * @version 0.0.1-SNAPSHOT
 * @since 2017年12月06日 17时34分
 */

@Controller
@RequestMapping("load")
public class LoadController {

    @Autowired
    private ServerService serverService;

    @Autowired
    private ServerTypeService serverTypeService;

    @Autowired
    private ProjectService projectService;

    /**
     * this method is only for Controller test, make sure that a Controller you write visit successfully
     * visit "http://localhost:8080/testController" after running, you can get a message
     * @return
     */
    @RequestMapping("index")
    public String index(HttpServletRequest request){

        List<Server> servers = serverService.findAllList();
        for (Server server : servers) {
            int typeId = server.getType().getId();
            ServerType serverType = serverTypeService.get(typeId);
            server.setType(serverType);
        }
        List<Project> projects = projectService.findAllList();

        request.setAttribute("servers", servers);
        request.setAttribute("projects", projects);

        return "load/index";
    }


    @RequestMapping("program")
    public String program(HttpServletRequest request,
        int[] projects, int[] servers, int[] linkedProjects, int[] linkedServers){

        // 从数据库中查询出相关数据
        List<Project> projectList = findProjectById(projects);
        List<Server> serverList = findServerById(servers);
        List<Project> linkedProjectList = findLPById(linkedProjects);
        List<Server> linkedServerList = findLSById(linkedServers);

        // server负载计算的专用数组
        double[] serverRemainMemory = new double[serverList.size()];
        for (int i = 0; i < serverRemainMemory.length; i++) {
            Server server = serverList.get(i);
            // 初始化的内存为服务器全部内存
            serverRemainMemory[i] = server.getMemory();
        }

        // 将定死的项目预先放入服务器
        for (int i = 0; i<linkedProjectList.size(); i++) {
            Project project = linkedProjectList.get(i);
            Server server = linkedServerList.get(i);
            // 找到相应的服务器放入，并将内存减少
            double takenMemory = calTakenMemory(project.getMemoryInit(), project.getMemoryMax());
            for (int serverIndex = 0; serverIndex < serverList.size(); serverIndex++) {
                Server uncheckedServer = serverList.get(serverIndex);
                if (uncheckedServer.getId() == server.getId()) {
                    uncheckedServer.getProjects().add(project);
                    serverRemainMemory[serverIndex] -= takenMemory;
                }
            }
        }

        // 将传入的项目每次寻找剩余内存最大的服务器放入
        for (Project project : projectList) {
            double takenMemory = calTakenMemory(project.getMemoryInit(), project.getMemoryMax());
            int maxServerIndex = getMaxIndex(serverRemainMemory);

            // 放入服务器
            Server server = serverList.get(maxServerIndex);
            server.getProjects().add(project);
            // 内存相应减少
            serverRemainMemory[maxServerIndex] -= takenMemory;
        }

        // 最终将使用的内存赋值给服务器，以便前段图标访问
        for (int i = 0; i<serverList.size(); i++) {
            Server server = serverList.get(i);
            server.setUsed(server.getMemory() - serverRemainMemory[i]);
        }

        request.setAttribute("servers", serverList);

        return "server";
    }

    private int getMaxIndex(double[] memory) {
        int maxIndex = 0;
        double maxValue = memory[0];
        for (int i = 0; i<memory.length; i++) {
            if (memory[i] > maxValue) {
                maxValue = memory[i];
                maxIndex = i;
            }
        }
        return maxIndex;
    }

    private double calTakenMemory(double init, double max) {
        return (init + max) / 2.0;
    }

    private List<Server> findLSById(int[] linkedServers) {
        List<Server> linkedServerList = new ArrayList<>(linkedServers.length);
        for (int linkedServerId:linkedServers) {
            Server linkedServer = serverService.get(linkedServerId);
            linkedServer.setProjects(new ArrayList<>(0));
            linkedServerList.add(linkedServer);
        }
        return linkedServerList;
    }

    private List<Project> findLPById(int[] linkedProjects) {
        List<Project> linkedProjectList = new ArrayList<>(linkedProjects.length);
        for (int linkedProjectId:linkedProjects) {
            Project linkedProject = projectService.get(linkedProjectId);
            linkedProject.setServers(new ArrayList<>(0));
            linkedProjectList.add(linkedProject);
        }
        return linkedProjectList;
    }

    private List<Server> findServerById(int[] servers) {
        List<Server> serverList = new ArrayList<>(servers.length);
        for (int serverId:servers) {
            Server server = serverService.get(serverId);
            server.setProjects(new ArrayList<>(0));

            int typeId = server.getType().getId();
            ServerType serverType = serverTypeService.get(typeId);
            server.setType(serverType);

            serverList.add(server);
        }
        return serverList;
    }

    private List<Project> findProjectById(int[] projects) {
        List<Project> projectList = new ArrayList<>(projects.length);
        for (int projectId:projects) {
            Project project = projectService.get(projectId);
            project.setServers(new ArrayList<>(0));
            projectList.add(project);
        }
        return projectList;
    }



}
